﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Base;

namespace UtilZ.Dotnet.Ex.Communication.Net.Tcp
{
    /// <summary>
    /// TCP客户端初始化参数
    /// </summary>
    public class NetTcpClientInitPara : ClientInitParaAbs
    {
        /// <summary>
        /// Tcp连接建立类型
        /// </summary>
        private ConnectTypes _connectType;
        /// <summary>
        /// Tcp连接建立类型
        /// </summary>
        internal ConnectTypes ConnectType
        {
            get { return _connectType; }
        }

        private readonly Socket _client = null;
        /// <summary>
        /// 被动连接监听到的Socket
        /// </summary>
        public Socket Client
        {
            get { return _client; }
        }

        private readonly EndPoint _remoteEndPoint;
        /// <summary>
        /// 主动连接时,对方EndPoint
        /// </summary>
        public EndPoint RemoteEndPoint
        {
            get { return _remoteEndPoint; }
        }

        /// <summary>
        /// 主动连接时,本地指定终节点
        /// </summary>
        public EndPoint LocalEndPoint { get; set; } = null;

        /// <summary>
        /// 是否接收数据[true:接收数据;false:只发送数据]
        /// </summary>
        public bool ReceiveData { get; set; } = true;

        /// <summary>
        /// 使用的IP协议类型
        /// </summary>
        public InterNetworkType InterNetwork { get; set; } = InterNetworkType.All;

        /// <summary>
        /// 是否保活连接[true:保活连接;false;顺其自然]
        /// </summary>
        public bool KeepAlive { get; set; } = false;

        /// <summary>
        /// 离最后一次收发数据后,多长时间触发保活操作,单位秒
        /// </summary>
        public int KeepAliveTimeSeconds { get; set; } = 30;

        /// <summary>
        /// 触发保活操作间隔,单位秒
        /// </summary>
        public int KeepAliveIntervalSeconds { get; set; } = 15;

        /// <summary>
        /// 触发保活操作次数,即发送该次数未收到回应,认为tcp连接断开
        /// </summary>
        public int KeepRetryCount { get; set; } = 3;

        /// <summary>
        /// 接收线程名称
        /// </summary>
        public string ReceiveThreadName { get; set; }


        private int _receiveBufferSize = -1;
        /// <summary>
        /// 接收数据缓冲区大小,大于0有效,小于等于0使用默认值
        /// </summary>
        public int ReceiveBufferSize
        {
            get { return _receiveBufferSize; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "单次接收数据包不能小于等于0");
                }

                _receiveBufferSize = value;
            }
        }

        private int _sendBufferSize = -1;
        /// <summary>
        /// 发送数据缓冲区大小,大于0有效,小于等于0使用默认值
        /// </summary>
        public int SendBufferSize
        {
            get { return _sendBufferSize; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "发送缓存不能小于等于0");
                }

                _sendBufferSize = value;
            }
        }

        private int _asyncReceiveStackDepth = 1000;
        /// <summary>
        /// 异步接收数据堆栈深度,该决定在大数据传输时每接收多次数据切换一次线程,以避免堆栈溢出.太小切换线程过于频繁,太大则会溢出.
        /// </summary>
        public int AsyncReceiveStackDepth
        {
            get { return _asyncReceiveStackDepth; }
            set
            {
                if (value < 10)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "异步接收数据堆栈深度不能小于10");
                }

                if (value > 10000)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), $"异步接收数据堆栈深度不能大于1000000");
                }

                _asyncReceiveStackDepth = value;
            }
        }


        private int _receiveDataSize = NetHelper.TCP_PACKAGE / 2;
        /// <summary>
        /// 单次接收数据包大小,此值为解析缓存大小值的一半
        /// </summary>
        public int ReceiveDataSize
        {
            get { return _receiveDataSize; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "单次接收数据包不能小于等于0");
                }

                //if (value > this._bufferSize)
                //{
                //    throw new ArgumentOutOfRangeException(nameof(value), $"单次接收数据包大小不能大于解析缓存大小\"{this._bufferSize}\"");
                //}
                _receiveDataSize = value;
            }
        }

        private int _bufferSize = NetHelper.TCP_PACKAGE;
        /// <summary>
        /// 解析缓存大小
        /// </summary>
        public int BufferSize
        {
            get { return _bufferSize; }
            set
            {
                //最小缓存4k
                //if (value <= this._receiveDataSize)
                //{
                //    throw new ArgumentOutOfRangeException(nameof(value), $"解析缓存不能小于单次接收数据包大小\"{this._receiveDataSize}\"");
                //}

                _bufferSize = value;
            }
        }

        private double _bufferSizeFactory = 0.5d;
        /// <summary>
        /// 解析缓存大小动态调整因子
        /// </summary>
        public double BufferSizeFactory
        {
            get { return _bufferSizeFactory; }
            set
            {
                if (value <= 0.0d)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), $"解析缓存大小动态调整因子不能小于等于0,值\"{value}\"无效");
                }

                _bufferSizeFactory = value;
            }
        }

        private int _bufferSizeLimit = 100000000;
        /// <summary>
        /// 解析缓存大小动态调整上限
        /// </summary>
        public int BufferSizeLimit
        {
            get { return _bufferSizeLimit; }
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), $"解析缓存大小动态调整上限不能小于等于0,值\"{value}\"无效");
                }

                _bufferSizeLimit = value;
            }
        }

        private int _reconnectIntervalMilliseconds = 1000;
        /// <summary>
        /// 主动连接断开后，重连间隔,默认1000毫秒
        /// </summary>
        public int ReconnectIntervalMilliseconds
        {
            get { return _reconnectIntervalMilliseconds; }
            set
            {
                if (this._connectType == ConnectTypes.Active && value < 1)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "重连接间隔不能小于等1毫秒");
                }

                _reconnectIntervalMilliseconds = value;
            }
        }

        /// <summary>
        /// 最大接收空数据次数,超过该次数认为tcp连接意外断开,小于0表示无限制.默认为-1
        /// </summary>
        public int MaxReceiveEmpyDataCount { get; set; } = -1;

        /// <summary>
        /// 安全证书
        /// </summary>
        public X509Certificate Certificate { get; set; } = null;

        /// <summary>
        /// 发送超时时长,单位:毫秒.大于0有效,小于等于0使用默认值
        /// </summary>
        public int SendMillisecondsTimeout { get; set; } = System.Threading.Timeout.Infinite;

        /// <summary>
        /// 发送超时时长,单位:毫秒.大于0有效,小于等于0使用默认值
        /// </summary>
        public int ReceiveMillisecondsTimeout { get; set; } = System.Threading.Timeout.Infinite;

        /// <summary>
        /// 同步接收数据连续发生错误时，最大重试次数，当超过此值时便会断开连接
        /// </summary>
        public int SynReceiveErrorMaxRepeatCount { get; set; } = 3;

        /// <summary>
        /// 监听到的Socket连接参数
        /// </summary>
        public AcceptSocketArgs SocketArgs { get; private set; } = null;




        /// <summary>
        /// 构造函数-监听连接
        /// </summary>
        /// <param name="unpacker">分包器</param>
        /// <param name="client">监听到的Socket连接</param>
        /// <exception cref="ArgumentNullException">dataOutput或receiveEndPoint为null将抛出异常</exception>
        public NetTcpClientInitPara(IUnpacker unpacker, Socket client)
            : base(unpacker)
        {
            if (client == null)
            {
                throw new ArgumentNullException(nameof(client));
            }

            this._remoteEndPoint = client.RemoteEndPoint;
            this._client = client;
            this._connectType = ConnectTypes.Passive;
        }

        /// <summary>
        /// 构造函数-监听连接
        /// </summary>
        /// <param name="unpacker">分包器</param>
        /// <param name="args">监听到的Socket连接参数</param>
        /// <exception cref="ArgumentNullException">dataOutput或receiveEndPoint为null将抛出异常</exception>
        public NetTcpClientInitPara(IUnpacker unpacker, AcceptSocketArgs args)
            : base(unpacker)
        {
            if (args == null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            this._remoteEndPoint = args.Client.RemoteEndPoint;
            this._client = args.Client;
            this._connectType = ConnectTypes.Passive;
            this.SocketArgs = args;
        }

        /// <summary>
        /// 构造函数-主动连接
        /// </summary>
        /// <param name="unpacker">分包器</param>
        /// <param name="dstEndPoint">目标EndPoint</param>
        /// <exception cref="ArgumentNullException">dataOutput或receiveEndPoint为null将抛出异常</exception>
        public NetTcpClientInitPara(IUnpacker unpacker, EndPoint dstEndPoint)
            : base(unpacker)
        {
            if (dstEndPoint == null)
            {
                throw new ArgumentNullException(nameof(dstEndPoint));
            }

            this._remoteEndPoint = dstEndPoint;
            this._connectType = ConnectTypes.Active;
        }

    }
}
